/* src/interfaces/ecpg/pgtypeslib/numeric.c */

#include "postgres_fe.h"

#include <ctype.h>
#include <float.h>
#include <limits.h>

#include "pgtypes_error.h"
#include "pgtypes_numeric.h"
#include "pgtypeslib_extern.h"

#define Max(x, y)				((x) > (y) ? (x) : (y))
#define Min(x, y)				((x) < (y) ? (x) : (y))

#define init_var(v)				memset(v,0,sizeof(numeric))

#define digitbuf_alloc(size) ((NumericDigit *) pgtypes_alloc(size))
#define digitbuf_free(buf)		\
	   do { \
				 if ((buf) != NULL) \
						  free(buf); \
		  } while (0)


/* ----------
 *	alloc_var() -
 *
 *	分配一个包含ndigits个数字的缓冲区（加上一个用于舍入的备用数字）
 * ----------
 */
static int fc_alloc_var(numeric *fc_var, int fc_ndigits)
{
	digitbuf_free(fc_var->buf);
	fc_var->buf = digitbuf_alloc(fc_ndigits + 1);
	if (fc_var->buf == NULL)
		return -1;
	fc_var->buf[0] = 0;
	fc_var->digits = fc_var->buf + 1;
	fc_var->ndigits = fc_ndigits;
	return 0;
}

numeric *
PGTYPESnumeric_new(void)
{
	numeric    *fc_var;

	if ((fc_var = (numeric *) pgtypes_alloc(sizeof(numeric))) == NULL)
		return NULL;

	if (fc_alloc_var(fc_var, 0) < 0)
	{
		free(fc_var);
		return NULL;
	}

	return fc_var;
}

decimal *
PGTYPESdecimal_new(void)
{
	decimal    *fc_var;

	if ((fc_var = (decimal *) pgtypes_alloc(sizeof(decimal))) == NULL)
		return NULL;

	memset(fc_var, 0, sizeof(decimal));

	return fc_var;
}

/* ----------
 * set_var_from_str()
 *
 *	解析字符串并将数字放入变量中
 * ----------
 */
static int fc_set_var_from_str(char *fc_str, char **fc_ptr, numeric *fc_dest)
{
	bool		fc_have_dp = false;
	int			fc_i = 0;

	errno = 0;
	*fc_ptr = fc_str;
	while (*(*fc_ptr))
	{
		if (!isspace((unsigned char) *(*fc_ptr)))
			break;
		(*fc_ptr)++;
	}

	if (pg_strncasecmp(*fc_ptr, "NaN", 3) == 0)
	{
		*fc_ptr += 3;
		fc_dest->sign = NUMERIC_NAN;

		/* 应该只剩下空格 */
		while (*(*fc_ptr))
		{
			if (!isspace((unsigned char) *(*fc_ptr)))
			{
				errno = PGTYPES_NUM_BAD_NUMERIC;
				return -1;
			}
			(*fc_ptr)++;
		}

		return 0;
	}

	if (fc_alloc_var(fc_dest, strlen((*fc_ptr))) < 0)
		return -1;
	fc_dest->weight = -1;
	fc_dest->dscale = 0;
	fc_dest->sign = NUMERIC_POS;

	switch (*(*fc_ptr))
	{
		case '+':
			fc_dest->sign = NUMERIC_POS;
			(*fc_ptr)++;
			break;

		case '-':
			fc_dest->sign = NUMERIC_NEG;
			(*fc_ptr)++;
			break;
	}

	if (*(*fc_ptr) == '.')
	{
		fc_have_dp = true;
		(*fc_ptr)++;
	}

	if (!isdigit((unsigned char) *(*fc_ptr)))
	{
		errno = PGTYPES_NUM_BAD_NUMERIC;
		return -1;
	}

	while (*(*fc_ptr))
	{
		if (isdigit((unsigned char) *(*fc_ptr)))
		{
			fc_dest->digits[fc_i++] = *(*fc_ptr)++ - '0';
			if (!fc_have_dp)
				fc_dest->weight++;
			else
				fc_dest->dscale++;
		}
		else if (*(*fc_ptr) == '.')
		{
			if (fc_have_dp)
			{
				errno = PGTYPES_NUM_BAD_NUMERIC;
				return -1;
			}
			fc_have_dp = true;
			(*fc_ptr)++;
		}
		else
			break;
	}
	fc_dest->ndigits = fc_i;

	/* 处理指数（如果有的话） */
	if (*(*fc_ptr) == 'e' || *(*fc_ptr) == 'E')
	{
		long		fc_exponent;
		char	   *fc_endptr;

		(*fc_ptr)++;
		fc_exponent = strtol(*fc_ptr, &fc_endptr, 10);
		if (fc_endptr == (*fc_ptr))
		{
			errno = PGTYPES_NUM_BAD_NUMERIC;
			return -1;
		}
		(*fc_ptr) = fc_endptr;
		if (fc_exponent >= INT_MAX / 2 || fc_exponent <= -(INT_MAX / 2))
		{
			errno = PGTYPES_NUM_BAD_NUMERIC;
			return -1;
		}
		fc_dest->weight += (int) fc_exponent;
		fc_dest->dscale -= (int) fc_exponent;
		if (fc_dest->dscale < 0)
			fc_dest->dscale = 0;
	}

	/* 应该只剩下空格 */
	while (*(*fc_ptr))
	{
		if (!isspace((unsigned char) *(*fc_ptr)))
		{
			errno = PGTYPES_NUM_BAD_NUMERIC;
			return -1;
		}
		(*fc_ptr)++;
	}

	/* 去掉任何前导零 */
	while (fc_dest->ndigits > 0 && *(fc_dest->digits) == 0)
	{
		(fc_dest->digits)++;
		(fc_dest->weight)--;
		(fc_dest->ndigits)--;
	}
	if (fc_dest->ndigits == 0)
		fc_dest->weight = 0;

	fc_dest->rscale = fc_dest->dscale;
	return 0;
}


/* ----------
 * get_str_from_var() -
 *
 *	将变量转换为文本表示（numeric_out的核心）。
 *	注意：变量的内容可能会因舍入而被修改！
 * ----------
 */
static char * fc_get_str_from_var(numeric *fc_var, int fc_dscale)
{
	char	   *fc_str;
	char	   *fc_cp;
	int			fc_i;
	int			fc_d;

	if (fc_var->sign == NUMERIC_NAN)
	{
		fc_str = (char *) pgtypes_alloc(4);
		if (fc_str == NULL)
			return NULL;
		sprintf(fc_str, "NaN");
		return fc_str;
	}

	/*
	 * 检查在打印值之前是否需要向上舍入，并执行舍入。
	 */
	fc_i = fc_dscale + fc_var->weight + 1;
	if (fc_i >= 0 && fc_var->ndigits > fc_i)
	{
		int			fc_carry = (fc_var->digits[fc_i] > 4) ? 1 : 0;

		fc_var->ndigits = fc_i;

		while (fc_carry)
		{
			fc_carry += fc_var->digits[--fc_i];
			fc_var->digits[fc_i] = fc_carry % 10;
			fc_carry /= 10;
		}

		if (fc_i < 0)
		{
			fc_var->digits--;
			fc_var->ndigits++;
			fc_var->weight++;
		}
	}
	else
		fc_var->ndigits = Max(0, Min(fc_i, fc_var->ndigits));

	/*
	 * 为结果分配空间
	 */
	if ((fc_str = (char *) pgtypes_alloc(Max(0, fc_dscale) + Max(0, fc_var->weight) + 4)) == NULL)
		return NULL;
	fc_cp = fc_str;

	/*
	 * 为负值输出一个负号
	 */
	if (fc_var->sign == NUMERIC_NEG)
		*fc_cp++ = '-';

	/*
	 * 输出小数点前的所有数字
	 */
	fc_i = Max(fc_var->weight, 0);
	fc_d = 0;

	while (fc_i >= 0)
	{
		if (fc_i <= fc_var->weight && fc_d < fc_var->ndigits)
			*fc_cp++ = fc_var->digits[fc_d++] + '0';
		else
			*fc_cp++ = '0';
		fc_i--;
	}

	/*
	 * 如果请求，输出小数点及其后面的所有数字。
	 */
	if (fc_dscale > 0)
	{
		*fc_cp++ = '.';
		while (fc_i >= -fc_dscale)
		{
			if (fc_i <= fc_var->weight && fc_d < fc_var->ndigits)
				*fc_cp++ = fc_var->digits[fc_d++] + '0';
			else
				*fc_cp++ = '0';
			fc_i--;
		}
	}

	/*
	 * 终止字符串并返回
	 */
	*fc_cp = '\0';
	return fc_str;
}

numeric *
PGTYPESnumeric_from_asc(char *fc_str, char **fc_endptr)
{
	numeric    *fc_value = (numeric *) pgtypes_alloc(sizeof(numeric));
	int			fc_ret;

	char	   *fc_realptr;
	char	  **fc_ptr = (fc_endptr != NULL) ? fc_endptr : &fc_realptr;

	if (!fc_value)
		return NULL;

	fc_ret = fc_set_var_from_str(fc_str, fc_ptr, fc_value);
	if (fc_ret)
	{
		PGTYPESnumeric_free(fc_value);
		return NULL;
	}

	return fc_value;
}

char * PGTYPESnumeric_to_asc(numeric *fc_num, int fc_dscale)
{
	numeric    *fc_numcopy = PGTYPESnumeric_new();
	char	   *fc_s;

	if (fc_numcopy == NULL)
		return NULL;

	if (PGTYPESnumeric_copy(fc_num, fc_numcopy) < 0)
	{
		PGTYPESnumeric_free(fc_numcopy);
		return NULL;
	}

	if (fc_dscale < 0)
		fc_dscale = fc_num->dscale;

	/* get_str_from_var可能会改变其参数 */
	fc_s = fc_get_str_from_var(fc_numcopy, fc_dscale);
	PGTYPESnumeric_free(fc_numcopy);
	return fc_s;
}

/* ----------
 * zero_var() -
 *
 *	将变量设为零。
 *	注意：rscale和dscale保持不变。
 * ----------
 */
static void fc_zero_var(numeric *fc_var)
{
	digitbuf_free(fc_var->buf);
	fc_var->buf = NULL;
	fc_var->digits = NULL;
	fc_var->ndigits = 0;
	fc_var->weight = 0;			/* 按惯例；实际上没有关系 */
	fc_var->sign = NUMERIC_POS;	/* 除了NAN之外的任何东西... */
}

void PGTYPESnumeric_free(numeric *fc_var)
{
	digitbuf_free(fc_var->buf);
	free(fc_var);
}

void PGTYPESdecimal_free(decimal *fc_var)
{
	free(fc_var);
}

/* ----------
 * cmp_abs() -
 *
 *	比较var1和var2的绝对值
 *	返回：	-1 表示 ABS(var1) < ABS(var2)
 *				0  表示 ABS(var1) == ABS(var2)
 *				1  表示 ABS(var1) > ABS(var2)
 * ----------
 */
static int fc_cmp_abs(numeric *fc_var1, numeric *fc_var2)
{
	int			fc_i1 = 0;
	int			fc_i2 = 0;
	int			fc_w1 = fc_var1->weight;
	int			fc_w2 = fc_var2->weight;
	int			fc_stat;

	while (fc_w1 > fc_w2 && fc_i1 < fc_var1->ndigits)
	{
		if (fc_var1->digits[fc_i1++] != 0)
			return 1;
		fc_w1--;
	}
	while (fc_w2 > fc_w1 && fc_i2 < fc_var2->ndigits)
	{
		if (fc_var2->digits[fc_i2++] != 0)
			return -1;
		fc_w2--;
	}

	if (fc_w1 == fc_w2)
	{
		while (fc_i1 < fc_var1->ndigits && fc_i2 < fc_var2->ndigits)
		{
			fc_stat = fc_var1->digits[fc_i1++] - fc_var2->digits[fc_i2++];
			if (fc_stat)
			{
				if (fc_stat > 0)
					return 1;
				return -1;
			}
		}
	}

	while (fc_i1 < fc_var1->ndigits)
	{
		if (fc_var1->digits[fc_i1++] != 0)
			return 1;
	}
	while (fc_i2 < fc_var2->ndigits)
	{
		if (fc_var2->digits[fc_i2++] != 0)
			return -1;
	}

	return 0;
}


/* ----------
 * add_abs() -
 *
 *	将两个变量的绝对值相加到结果中。
 *	结果可能指向其中一个操作数而不危险。
 * ----------
 */
static int fc_add_abs(numeric *fc_var1, numeric *fc_var2, numeric *fc_result)
{
	NumericDigit *fc_res_buf;
	NumericDigit *fc_res_digits;
	int			fc_res_ndigits;
	int			fc_res_weight;
	int			fc_res_rscale;
	int			fc_res_dscale;
	int			fc_i,
				fc_i1,
				fc_i2;
	int			fc_carry = 0;

	/* 将这些值复制到局部变量中，以提高内部循环的速度 */
	int			fc_var1ndigits = fc_var1->ndigits;
	int			fc_var2ndigits = fc_var2->ndigits;
	NumericDigit *fc_var1digits = fc_var1->digits;
	NumericDigit *fc_var2digits = fc_var2->digits;

	fc_res_weight = Max(fc_var1->weight, fc_var2->weight) + 1;
	fc_res_rscale = Max(fc_var1->rscale, fc_var2->rscale);
	fc_res_dscale = Max(fc_var1->dscale, fc_var2->dscale);
	fc_res_ndigits = fc_res_rscale + fc_res_weight + 1;
	if (fc_res_ndigits <= 0)
		fc_res_ndigits = 1;

	if ((fc_res_buf = digitbuf_alloc(fc_res_ndigits)) == NULL)
		return -1;
	fc_res_digits = fc_res_buf;

	fc_i1 = fc_res_rscale + fc_var1->weight + 1;
	fc_i2 = fc_res_rscale + fc_var2->weight + 1;
	for (fc_i = fc_res_ndigits - 1; fc_i >= 0; fc_i--)
	{
		fc_i1--;
		fc_i2--;
		if (fc_i1 >= 0 && fc_i1 < fc_var1ndigits)
			fc_carry += fc_var1digits[fc_i1];
		if (fc_i2 >= 0 && fc_i2 < fc_var2ndigits)
			fc_carry += fc_var2digits[fc_i2];

		if (fc_carry >= 10)
		{
			fc_res_digits[fc_i] = fc_carry - 10;
			fc_carry = 1;
		}
		else
		{
			fc_res_digits[fc_i] = fc_carry;
			fc_carry = 0;
		}
	}

	while (fc_res_ndigits > 0 && *fc_res_digits == 0)
	{
		fc_res_digits++;
		fc_res_weight--;
		fc_res_ndigits--;
	}
	while (fc_res_ndigits > 0 && fc_res_digits[fc_res_ndigits - 1] == 0)
		fc_res_ndigits--;

	if (fc_res_ndigits == 0)
		fc_res_weight = 0;

	digitbuf_free(fc_result->buf);
	fc_result->ndigits = fc_res_ndigits;
	fc_result->buf = fc_res_buf;
	fc_result->digits = fc_res_digits;
	fc_result->weight = fc_res_weight;
	fc_result->rscale = fc_res_rscale;
	fc_result->dscale = fc_res_dscale;

	return 0;
}


/* ----------
 * sub_abs() -
 *
 *	从var1的绝对值中减去var2的绝对值
 *	并存储在结果中。结果可能指向其中一个操作数
 *	而不危险。
 *
 *	ABS(var1) 必须大于或等于 ABS(var2) !!!
 * ----------
 */
static int fc_sub_abs(numeric *fc_var1, numeric *fc_var2, numeric *fc_result)
{
	NumericDigit *fc_res_buf;
	NumericDigit *fc_res_digits;
	int			fc_res_ndigits;
	int			fc_res_weight;
	int			fc_res_rscale;
	int			fc_res_dscale;
	int			fc_i,
				fc_i1,
				fc_i2;
	int			fc_borrow = 0;

	/* 将这些值复制到局部变量中，以提高内部循环的速度 */
	int			fc_var1ndigits = fc_var1->ndigits;
	int			fc_var2ndigits = fc_var2->ndigits;
	NumericDigit *fc_var1digits = fc_var1->digits;
	NumericDigit *fc_var2digits = fc_var2->digits;

	fc_res_weight = fc_var1->weight;
	fc_res_rscale = Max(fc_var1->rscale, fc_var2->rscale);
	fc_res_dscale = Max(fc_var1->dscale, fc_var2->dscale);
	fc_res_ndigits = fc_res_rscale + fc_res_weight + 1;
	if (fc_res_ndigits <= 0)
		fc_res_ndigits = 1;

	if ((fc_res_buf = digitbuf_alloc(fc_res_ndigits)) == NULL)
		return -1;
	fc_res_digits = fc_res_buf;

	fc_i1 = fc_res_rscale + fc_var1->weight + 1;
	fc_i2 = fc_res_rscale + fc_var2->weight + 1;
	for (fc_i = fc_res_ndigits - 1; fc_i >= 0; fc_i--)
	{
		fc_i1--;
		fc_i2--;
		if (fc_i1 >= 0 && fc_i1 < fc_var1ndigits)
			fc_borrow += fc_var1digits[fc_i1];
		if (fc_i2 >= 0 && fc_i2 < fc_var2ndigits)
			fc_borrow -= fc_var2digits[fc_i2];

		if (fc_borrow < 0)
		{
			fc_res_digits[fc_i] = fc_borrow + 10;
			fc_borrow = -1;
		}
		else
		{
			fc_res_digits[fc_i] = fc_borrow;
			fc_borrow = 0;
		}
	}

	while (fc_res_ndigits > 0 && *fc_res_digits == 0)
	{
		fc_res_digits++;
		fc_res_weight--;
		fc_res_ndigits--;
	}
	while (fc_res_ndigits > 0 && fc_res_digits[fc_res_ndigits - 1] == 0)
		fc_res_ndigits--;

	if (fc_res_ndigits == 0)
		fc_res_weight = 0;

	digitbuf_free(fc_result->buf);
	fc_result->ndigits = fc_res_ndigits;
	fc_result->buf = fc_res_buf;
	fc_result->digits = fc_res_digits;
	fc_result->weight = fc_res_weight;
	fc_result->rscale = fc_res_rscale;
	fc_result->dscale = fc_res_dscale;

	return 0;
}

/* ----------
 * add_var() -
 *
 *	在变量级别执行加法功能的完整版本（处理符号）。
 *	结果也可能指向其中一个操作数而不危险。
 * ----------
 */
int PGTYPESnumeric_add(numeric *fc_var1, numeric *fc_var2, numeric *fc_result)
{
	/*
	 * 根据信号决定这两个变量该怎么做
	 */
	if (fc_var1->sign == NUMERIC_POS)
	{
		if (fc_var2->sign == NUMERIC_POS)
		{
			/*
			 * 两个都是正数 结果 = +(ABS(var1) + ABS(var2))
			 */
			if (fc_add_abs(fc_var1, fc_var2, fc_result) != 0)
				return -1;
			fc_result->sign = NUMERIC_POS;
		}
		else
		{
			/*
			 * var1是正数，var2是负数 必须比较绝对值
			 */
			switch (fc_cmp_abs(fc_var1, fc_var2))
			{
				case 0:
					/* ----------
					 * ABS(var1) == ABS(var2)
					 * 结果 = 零
					 * ----------
					 */
					fc_zero_var(fc_result);
					fc_result->rscale = Max(fc_var1->rscale, fc_var2->rscale);
					fc_result->dscale = Max(fc_var1->dscale, fc_var2->dscale);
					break;

				case 1:
					/* ----------
					 * ABS(var1) > ABS(var2)
					 * 结果 = +(ABS(var1) - ABS(var2))
					 * ----------
					 */
					if (fc_sub_abs(fc_var1, fc_var2, fc_result) != 0)
						return -1;
					fc_result->sign = NUMERIC_POS;
					break;

				case -1:
					/* ----------
					 * ABS(var1) < ABS(var2)
					 * 结果 = -(ABS(var2) - ABS(var1))
					 * ----------
					 */
					if (fc_sub_abs(fc_var2, fc_var1, fc_result) != 0)
						return -1;
					fc_result->sign = NUMERIC_NEG;
					break;
			}
		}
	}
	else
	{
		if (fc_var2->sign == NUMERIC_POS)
		{
			/* ----------
			 * var1是负数，var2是正数
			 * 必须比较绝对值
			 * ----------
			 */
			switch (fc_cmp_abs(fc_var1, fc_var2))
			{
				case 0:
					/* ----------
					 * ABS(var1) == ABS(var2)
					 * 结果 = 零
					 * ----------
					 */
					fc_zero_var(fc_result);
					fc_result->rscale = Max(fc_var1->rscale, fc_var2->rscale);
					fc_result->dscale = Max(fc_var1->dscale, fc_var2->dscale);
					break;

				case 1:
					/* ----------
					 * ABS(var1) > ABS(var2)
					 * result = -(ABS(var1) - ABS(var2))
					 * ----------
					 */
					if (fc_sub_abs(fc_var1, fc_var2, fc_result) != 0)
						return -1;
					fc_result->sign = NUMERIC_NEG;
					break;

				case -1:
					/* ----------
					 * ABS(var1) < ABS(var2)
					 * result = +(ABS(var2) - ABS(var1))
					 * ----------
					 */
					if (fc_sub_abs(fc_var2, fc_var1, fc_result) != 0)
						return -1;
					fc_result->sign = NUMERIC_POS;
					break;
			}
		}
		else
		{
			/* ----------
			 * 两者都是负数
			 * result = -(ABS(var1) + ABS(var2))
			 * ----------
			 */
			if (fc_add_abs(fc_var1, fc_var2, fc_result) != 0)
				return -1;
			fc_result->sign = NUMERIC_NEG;
		}
	}

	return 0;
}


/* ----------
 * sub_var() -
 *
 *	在变量级别上实现完整的减法功能（处理符号）。
 *	result 也可能指向其中一个操作数而不会有危险。
 * ----------
 */
int PGTYPESnumeric_sub(numeric *fc_var1, numeric *fc_var2, numeric *fc_result)
{
	/*
	 * 根据信号决定这两个变量该怎么做
	 */
	if (fc_var1->sign == NUMERIC_POS)
	{
		if (fc_var2->sign == NUMERIC_NEG)
		{
			/* ----------
			 * var1 是正数，var2 是负数
			 * result = +(ABS(var1) + ABS(var2))
			 * ----------
			 */
			if (fc_add_abs(fc_var1, fc_var2, fc_result) != 0)
				return -1;
			fc_result->sign = NUMERIC_POS;
		}
		else
		{
			/* ----------
			 * 两者都是正数
			 * 必须比较绝对值
			 * ----------
			 */
			switch (fc_cmp_abs(fc_var1, fc_var2))
			{
				case 0:
					/* ----------
					 * ABS(var1) == ABS(var2)
					 * 结果 = 零
					 * ----------
					 */
					fc_zero_var(fc_result);
					fc_result->rscale = Max(fc_var1->rscale, fc_var2->rscale);
					fc_result->dscale = Max(fc_var1->dscale, fc_var2->dscale);
					break;

				case 1:
					/* ----------
					 * ABS(var1) > ABS(var2)
					 * 结果 = +(ABS(var1) - ABS(var2))
					 * ----------
					 */
					if (fc_sub_abs(fc_var1, fc_var2, fc_result) != 0)
						return -1;
					fc_result->sign = NUMERIC_POS;
					break;

				case -1:
					/* ----------
					 * ABS(var1) < ABS(var2)
					 * 结果 = -(ABS(var2) - ABS(var1))
					 * ----------
					 */
					if (fc_sub_abs(fc_var2, fc_var1, fc_result) != 0)
						return -1;
					fc_result->sign = NUMERIC_NEG;
					break;
			}
		}
	}
	else
	{
		if (fc_var2->sign == NUMERIC_NEG)
		{
			/* ----------
			 * 两者都是负数
			 * 必须比较绝对值
			 * ----------
			 */
			switch (fc_cmp_abs(fc_var1, fc_var2))
			{
				case 0:
					/* ----------
					 * ABS(var1) == ABS(var2)
					 * 结果 = 零
					 * ----------
					 */
					fc_zero_var(fc_result);
					fc_result->rscale = Max(fc_var1->rscale, fc_var2->rscale);
					fc_result->dscale = Max(fc_var1->dscale, fc_var2->dscale);
					break;

				case 1:
					/* ----------
					 * ABS(var1) > ABS(var2)
					 * result = -(ABS(var1) - ABS(var2))
					 * ----------
					 */
					if (fc_sub_abs(fc_var1, fc_var2, fc_result) != 0)
						return -1;
					fc_result->sign = NUMERIC_NEG;
					break;

				case -1:
					/* ----------
					 * ABS(var1) < ABS(var2)
					 * result = +(ABS(var2) - ABS(var1))
					 * ----------
					 */
					if (fc_sub_abs(fc_var2, fc_var1, fc_result) != 0)
						return -1;
					fc_result->sign = NUMERIC_POS;
					break;
			}
		}
		else
		{
			/* ----------
			 * var1 是负数，var2 是正数
			 * result = -(ABS(var1) + ABS(var2))
			 * ----------
			 */
			if (fc_add_abs(fc_var1, fc_var2, fc_result) != 0)
				return -1;
			fc_result->sign = NUMERIC_NEG;
		}
	}

	return 0;
}

/* ----------
 * mul_var() -
 *
 *	在变量级别进行乘法运算。 var1 * var2 的乘积存储在 result 中。
 *	result 的准确性由 global_rscale 决定。
 * ----------
 */
int PGTYPESnumeric_mul(numeric *fc_var1, numeric *fc_var2, numeric *fc_result)
{
	NumericDigit *fc_res_buf;
	NumericDigit *fc_res_digits;
	int			fc_res_ndigits;
	int			fc_res_weight;
	int			fc_res_sign;
	int			fc_i,
				fc_ri,
				fc_i1,
				fc_i2;
	long		fc_sum = 0;
	int			fc_global_rscale = fc_var1->rscale + fc_var2->rscale;

	fc_res_weight = fc_var1->weight + fc_var2->weight + 2;
	fc_res_ndigits = fc_var1->ndigits + fc_var2->ndigits + 1;
	if (fc_var1->sign == fc_var2->sign)
		fc_res_sign = NUMERIC_POS;
	else
		fc_res_sign = NUMERIC_NEG;

	if ((fc_res_buf = digitbuf_alloc(fc_res_ndigits)) == NULL)
		return -1;
	fc_res_digits = fc_res_buf;
	memset(fc_res_digits, 0, fc_res_ndigits);

	fc_ri = fc_res_ndigits;
	for (fc_i1 = fc_var1->ndigits - 1; fc_i1 >= 0; fc_i1--)
	{
		fc_sum = 0;
		fc_i = --fc_ri;

		for (fc_i2 = fc_var2->ndigits - 1; fc_i2 >= 0; fc_i2--)
		{
			fc_sum += fc_res_digits[fc_i] + fc_var1->digits[fc_i1] * fc_var2->digits[fc_i2];
			fc_res_digits[fc_i--] = fc_sum % 10;
			fc_sum /= 10;
		}
		fc_res_digits[fc_i] = fc_sum;
	}

	fc_i = fc_res_weight + fc_global_rscale + 2;
	if (fc_i >= 0 && fc_i < fc_res_ndigits)
	{
		fc_sum = (fc_res_digits[fc_i] > 4) ? 1 : 0;
		fc_res_ndigits = fc_i;
		fc_i--;
		while (fc_sum)
		{
			fc_sum += fc_res_digits[fc_i];
			fc_res_digits[fc_i--] = fc_sum % 10;
			fc_sum /= 10;
		}
	}

	while (fc_res_ndigits > 0 && *fc_res_digits == 0)
	{
		fc_res_digits++;
		fc_res_weight--;
		fc_res_ndigits--;
	}
	while (fc_res_ndigits > 0 && fc_res_digits[fc_res_ndigits - 1] == 0)
		fc_res_ndigits--;

	if (fc_res_ndigits == 0)
	{
		fc_res_sign = NUMERIC_POS;
		fc_res_weight = 0;
	}

	digitbuf_free(fc_result->buf);
	fc_result->buf = fc_res_buf;
	fc_result->digits = fc_res_digits;
	fc_result->ndigits = fc_res_ndigits;
	fc_result->weight = fc_res_weight;
	fc_result->rscale = fc_global_rscale;
	fc_result->sign = fc_res_sign;
	fc_result->dscale = fc_var1->dscale + fc_var2->dscale;

	return 0;
}

/*
 * 默认的除法缩放选择
 *
 * 返回适当的显示缩放用于除法结果，
 * 并将 global_rscale 设置为在 div_var 中使用的结果缩放。
 *
 * 注意，这必须在 div_var 之前调用。
 */
static int fc_select_div_scale(numeric *fc_var1, numeric *fc_var2, int *fc_rscale)
{
	int			fc_weight1,
				fc_weight2,
				fc_qweight,
				fc_i;
	NumericDigit fc_firstdigit1,
				fc_firstdigit2;
	int			fc_res_dscale;

	/*
	 * 除法的结果缩放在任何 SQL 标准中都未指定。
	 * 对于 PostgreSQL，我们选择一个显示缩放，使其至少
	 * 包含 NUMERIC_MIN_SIG_DIGITS 个有效数字，以确保 numeric 给出的结果
	 * 至少与 float8 一样精确；但使用的缩放不得低于
	 * 任一输入的显示缩放。
	 */

	/* 获取每个输入的实际（标准化）权重和首位数字 */

	fc_weight1 = 0;				/* 当 var1 为零时要使用的值 */
	fc_firstdigit1 = 0;
	for (fc_i = 0; fc_i < fc_var1->ndigits; fc_i++)
	{
		fc_firstdigit1 = fc_var1->digits[fc_i];
		if (fc_firstdigit1 != 0)
		{
			fc_weight1 = fc_var1->weight - fc_i;
			break;
		}
	}

	fc_weight2 = 0;				/* 当 var2 为零时要使用的值 */
	fc_firstdigit2 = 0;
	for (fc_i = 0; fc_i < fc_var2->ndigits; fc_i++)
	{
		fc_firstdigit2 = fc_var2->digits[fc_i];
		if (fc_firstdigit2 != 0)
		{
			fc_weight2 = fc_var2->weight - fc_i;
			break;
		}
	}

	/*
	 * 估算商的权重。如果两个首位数字相等，我们
	 * 不能确定，但假设 var1 小于 var2。
	 */
	fc_qweight = fc_weight1 - fc_weight2;
	if (fc_firstdigit1 <= fc_firstdigit2)
		fc_qweight--;

	/* 选择显示缩放 */
	fc_res_dscale = NUMERIC_MIN_SIG_DIGITS - fc_qweight;
	fc_res_dscale = Max(fc_res_dscale, fc_var1->dscale);
	fc_res_dscale = Max(fc_res_dscale, fc_var2->dscale);
	fc_res_dscale = Max(fc_res_dscale, NUMERIC_MIN_DISPLAY_SCALE);
	fc_res_dscale = Min(fc_res_dscale, NUMERIC_MAX_DISPLAY_SCALE);

	/* 选择结果缩放 */
	*fc_rscale = fc_res_dscale + 4;

	return fc_res_dscale;
}

int PGTYPESnumeric_div(numeric *fc_var1, numeric *fc_var2, numeric *fc_result)
{
	NumericDigit *fc_res_digits;
	int			fc_res_ndigits;
	int			fc_res_sign;
	int			fc_res_weight;
	numeric		fc_dividend;
	numeric		fc_divisor[10];
	int			fc_ndigits_tmp;
	int			fc_weight_tmp;
	int			fc_rscale_tmp;
	int			fc_ri;
	int			fc_i;
	long		fc_guess;
	long		fc_first_have;
	long		fc_first_div;
	int			fc_first_nextdigit;
	int			fc_stat = 0;
	int			fc_rscale;
	int			fc_res_dscale = fc_select_div_scale(fc_var1, fc_var2, &fc_rscale);
	int			fc_err = -1;
	NumericDigit *fc_tmp_buf;

	/*
	 * 首先检查除以零
	 */
	fc_ndigits_tmp = fc_var2->ndigits + 1;
	if (fc_ndigits_tmp == 1)
	{
		errno = PGTYPES_NUM_DIVIDE_ZERO;
		return -1;
	}

	/*
	 * 确定结果的符号、权重和计算的数字位数
	 */
	if (fc_var1->sign == fc_var2->sign)
		fc_res_sign = NUMERIC_POS;
	else
		fc_res_sign = NUMERIC_NEG;
	fc_res_weight = fc_var1->weight - fc_var2->weight + 1;
	fc_res_ndigits = fc_rscale + fc_res_weight;
	if (fc_res_ndigits <= 0)
		fc_res_ndigits = 1;

	/*
	 * 现在检查结果是否为零
	 */
	if (fc_var1->ndigits == 0)
	{
		fc_zero_var(fc_result);
		fc_result->rscale = fc_rscale;
		return 0;
	}

	/*
	 * 初始化局部变量
	 */
	init_var(&fc_dividend);
	for (fc_i = 1; fc_i < 10; fc_i++)
		init_var(&fc_divisor[fc_i]);

	/*
	 * 复制除数，前面添加一个零位
	 */
	fc_divisor[1].ndigits = fc_ndigits_tmp;
	fc_divisor[1].rscale = fc_var2->ndigits;
	fc_divisor[1].sign = NUMERIC_POS;
	fc_divisor[1].buf = digitbuf_alloc(fc_ndigits_tmp);
	if (fc_divisor[1].buf == NULL)
		goto done;
	fc_divisor[1].digits = fc_divisor[1].buf;
	fc_divisor[1].digits[0] = 0;
	memcpy(&(fc_divisor[1].digits[1]), fc_var2->digits, fc_ndigits_tmp - 1);

	/*
	 * 复制被除数
	 */
	fc_dividend.ndigits = fc_var1->ndigits;
	fc_dividend.weight = 0;
	fc_dividend.rscale = fc_var1->ndigits;
	fc_dividend.sign = NUMERIC_POS;
	fc_dividend.buf = digitbuf_alloc(fc_var1->ndigits);
	if (fc_dividend.buf == NULL)
		goto done;
	fc_dividend.digits = fc_dividend.buf;
	memcpy(fc_dividend.digits, fc_var1->digits, fc_var1->ndigits);

	/*
	 * 设置结果。先在一个临时缓冲区进行分配，以便我们在成功分配了
	 * 一个替代的缓冲区之前，不释放 result->buf。
	 */
	fc_tmp_buf = digitbuf_alloc(fc_res_ndigits + 2);
	if (fc_tmp_buf == NULL)
		goto done;
	digitbuf_free(fc_result->buf);
	fc_result->buf = fc_tmp_buf;
	fc_res_digits = fc_result->buf;
	fc_result->digits = fc_res_digits;
	fc_result->ndigits = fc_res_ndigits;
	fc_result->weight = fc_res_weight;
	fc_result->rscale = fc_rscale;
	fc_result->sign = fc_res_sign;
	fc_res_digits[0] = 0;

	fc_first_div = fc_divisor[1].digits[1] * 10;
	if (fc_ndigits_tmp > 2)
		fc_first_div += fc_divisor[1].digits[2];

	fc_first_have = 0;
	fc_first_nextdigit = 0;

	fc_weight_tmp = 1;
	fc_rscale_tmp = fc_divisor[1].rscale;

	for (fc_ri = 0; fc_ri <= fc_res_ndigits; fc_ri++)
	{
		fc_first_have = fc_first_have * 10;
		if (fc_first_nextdigit >= 0 && fc_first_nextdigit < fc_dividend.ndigits)
			fc_first_have += fc_dividend.digits[fc_first_nextdigit];
		fc_first_nextdigit++;

		fc_guess = (fc_first_have * 10) / fc_first_div + 1;
		if (fc_guess > 9)
			fc_guess = 9;

		while (fc_guess > 0)
		{
			if (fc_divisor[fc_guess].buf == NULL)
			{
				int			fc_i;
				long		fc_sum = 0;

				memcpy(&fc_divisor[fc_guess], &fc_divisor[1], sizeof(numeric));
				fc_divisor[fc_guess].buf = digitbuf_alloc(fc_divisor[fc_guess].ndigits);
				if (fc_divisor[fc_guess].buf == NULL)
					goto done;
				fc_divisor[fc_guess].digits = fc_divisor[fc_guess].buf;
				for (fc_i = fc_divisor[1].ndigits - 1; fc_i >= 0; fc_i--)
				{
					fc_sum += fc_divisor[1].digits[fc_i] * fc_guess;
					fc_divisor[fc_guess].digits[fc_i] = fc_sum % 10;
					fc_sum /= 10;
				}
			}

			fc_divisor[fc_guess].weight = fc_weight_tmp;
			fc_divisor[fc_guess].rscale = fc_rscale_tmp;

			fc_stat = fc_cmp_abs(&fc_dividend, &fc_divisor[fc_guess]);
			if (fc_stat >= 0)
				break;

			fc_guess--;
		}

		fc_res_digits[fc_ri + 1] = fc_guess;
		if (fc_stat == 0)
		{
			fc_ri++;
			break;
		}

		fc_weight_tmp--;
		fc_rscale_tmp++;

		if (fc_guess == 0)
			continue;

		if (fc_sub_abs(&fc_dividend, &fc_divisor[fc_guess], &fc_dividend) != 0)
			goto done;

		fc_first_nextdigit = fc_dividend.weight - fc_weight_tmp;
		fc_first_have = 0;
		if (fc_first_nextdigit >= 0 && fc_first_nextdigit < fc_dividend.ndigits)
			fc_first_have = fc_dividend.digits[fc_first_nextdigit];
		fc_first_nextdigit++;
	}

	fc_result->ndigits = fc_ri + 1;
	if (fc_ri == fc_res_ndigits + 1)
	{
		int			fc_carry = (fc_res_digits[fc_ri] > 4) ? 1 : 0;

		fc_result->ndigits = fc_ri;
		fc_res_digits[fc_ri] = 0;

		while (fc_carry && fc_ri > 0)
		{
			fc_carry += fc_res_digits[--fc_ri];
			fc_res_digits[fc_ri] = fc_carry % 10;
			fc_carry /= 10;
		}
	}

	while (fc_result->ndigits > 0 && *(fc_result->digits) == 0)
	{
		(fc_result->digits)++;
		(fc_result->weight)--;
		(fc_result->ndigits)--;
	}
	while (fc_result->ndigits > 0 && fc_result->digits[fc_result->ndigits - 1] == 0)
		(fc_result->ndigits)--;
	if (fc_result->ndigits == 0)
		fc_result->sign = NUMERIC_POS;

	fc_result->dscale = fc_res_dscale;
	fc_err = 0;					/* 如果我们已经走到这一步，返回成功 */

done:

	/*
	 * 清理
	 */
	if (fc_dividend.buf != NULL)
		digitbuf_free(fc_dividend.buf);

	for (fc_i = 1; fc_i < 10; fc_i++)
	{
		if (fc_divisor[fc_i].buf != NULL)
			digitbuf_free(fc_divisor[fc_i].buf);
	}

	return fc_err;
}


int PGTYPESnumeric_cmp(numeric *fc_var1, numeric *fc_var2)
{
	/* 使用 cmp_abs 函数计算结果 */

	/* 两者都是正数：使用 cmp_abs 进行正常比较 */
	if (fc_var1->sign == NUMERIC_POS && fc_var2->sign == NUMERIC_POS)
		return fc_cmp_abs(fc_var1, fc_var2);

	/* 两者都是负数：返回正常比较的反码 */
	if (fc_var1->sign == NUMERIC_NEG && fc_var2->sign == NUMERIC_NEG)
	{
		/*
		 * 我们不是反转结果，而是反转参数的顺序
		 */
		return fc_cmp_abs(fc_var2, fc_var1);
	}

	/* 一个是正数，一个是负数：简单 */
	if (fc_var1->sign == NUMERIC_POS && fc_var2->sign == NUMERIC_NEG)
		return 1;
	if (fc_var1->sign == NUMERIC_NEG && fc_var2->sign == NUMERIC_POS)
		return -1;

	errno = PGTYPES_NUM_BAD_NUMERIC;
	return INT_MAX;
}

int PGTYPESnumeric_from_int(signed int fc_int_val, numeric *fc_var)
{
	/* 隐式转换 */
	signed long int fc_long_int = fc_int_val;

	return PGTYPESnumeric_from_long(fc_long_int, fc_var);
}

int PGTYPESnumeric_from_long(signed long int fc_long_val, numeric *fc_var)
{
	/* 计算长整型数字的大小 */
	/* 一个数字 n 需要 log_10 n 位 */

	/*
	 * 然而我们每次将其乘以 10 进行比较，而不是计算
	 * 对数
	 */

	int			fc_size = 0;
	int			fc_i;
	signed long int fc_abs_long_val = fc_long_val;
	signed long int fc_extract;
	signed long int fc_reach_limit;

	if (fc_abs_long_val < 0)
	{
		fc_abs_long_val *= -1;
		fc_var->sign = NUMERIC_NEG;
	}
	else
		fc_var->sign = NUMERIC_POS;

	fc_reach_limit = 1;
	do
	{
		fc_size++;
		fc_reach_limit *= 10;
	} while (fc_reach_limit - 1 < fc_abs_long_val && fc_reach_limit <= LONG_MAX / 10);

	if (fc_reach_limit > LONG_MAX / 10)
	{
		/* 添加第一位数字和 .0 */
		fc_size += 2;
	}
	else
	{
		/* 始终添加 .0 */
		fc_size++;
		fc_reach_limit /= 10;
	}

	if (fc_alloc_var(fc_var, fc_size) < 0)
		return -1;

	fc_var->rscale = 1;
	fc_var->dscale = 1;
	fc_var->weight = fc_size - 2;

	fc_i = 0;
	do
	{
		fc_extract = fc_abs_long_val - (fc_abs_long_val % fc_reach_limit);
		fc_var->digits[fc_i] = fc_extract / fc_reach_limit;
		fc_abs_long_val -= fc_extract;
		fc_i++;
		fc_reach_limit /= 10;

		/*
		 * 如果 abs_long_val 达到 0，我们可以放弃，因为内存被
		 * 正确初始化并填充为 '0'，因此将 10000 转换为
		 * 只需一步就没问题
		 */
	} while (fc_abs_long_val > 0);

	return 0;
}

int PGTYPESnumeric_copy(numeric *fc_src, numeric *fc_dst)
{
	int			fc_i;

	if (fc_dst == NULL)
		return -1;
	fc_zero_var(fc_dst);

	fc_dst->weight = fc_src->weight;
	fc_dst->rscale = fc_src->rscale;
	fc_dst->dscale = fc_src->dscale;
	fc_dst->sign = fc_src->sign;

	if (fc_alloc_var(fc_dst, fc_src->ndigits) != 0)
		return -1;

	for (fc_i = 0; fc_i < fc_src->ndigits; fc_i++)
		fc_dst->digits[fc_i] = fc_src->digits[fc_i];

	return 0;
}

int PGTYPESnumeric_from_double(double fc_d, numeric *fc_dst)
{
	char		fc_buffer[DBL_DIG + 100];
	numeric    *fc_tmp;
	int			fc_i;

	if (sprintf(fc_buffer, "%.*g", DBL_DIG, fc_d) <= 0)
		return -1;

	if ((fc_tmp = PGTYPESnumeric_from_asc(fc_buffer, NULL)) == NULL)
		return -1;
	fc_i = PGTYPESnumeric_copy(fc_tmp, fc_dst);
	PGTYPESnumeric_free(fc_tmp);
	if (fc_i != 0)
		return -1;

	errno = 0;
	return 0;
}

static int fc_numericvar_to_double(numeric *fc_var, double *fc_dp)
{
	char	   *fc_tmp;
	double		fc_val;
	char	   *fc_endptr;
	numeric    *fc_varcopy = PGTYPESnumeric_new();

	if (fc_varcopy == NULL)
		return -1;

	if (PGTYPESnumeric_copy(fc_var, fc_varcopy) < 0)
	{
		PGTYPESnumeric_free(fc_varcopy);
		return -1;
	}

	fc_tmp = fc_get_str_from_var(fc_varcopy, fc_varcopy->dscale);
	PGTYPESnumeric_free(fc_varcopy);

	if (fc_tmp == NULL)
		return -1;

	/*
	 * strtod 在成功的情况下不会将 errno 重置为 0。
	 */
	errno = 0;
	fc_val = strtod(fc_tmp, &fc_endptr);
	if (errno == ERANGE)
	{
		free(fc_tmp);
		if (fc_val == 0)
			errno = PGTYPES_NUM_UNDERFLOW;
		else
			errno = PGTYPES_NUM_OVERFLOW;
		return -1;
	}

	/* 还不能释放 tmp，endptr 仍指向其中 */
	/* 不应该发生 ... */
	if (*fc_endptr != '\0')
	{
		/* 静默编译器，避免对无用测试的抱怨 */
		free(fc_tmp);
		errno = PGTYPES_NUM_BAD_NUMERIC;
		return -1;
	}
	free(fc_tmp);
	*fc_dp = fc_val;
	return 0;
}

int PGTYPESnumeric_to_double(numeric *fc_nv, double *fc_dp)
{
	double		fc_tmp;

	if (fc_numericvar_to_double(fc_nv, &fc_tmp) != 0)
		return -1;
	*fc_dp = fc_tmp;
	return 0;
}

int PGTYPESnumeric_to_int(numeric *fc_nv, int *fc_ip)
{
	long		fc_l;
	int			fc_i;

	if ((fc_i = PGTYPESnumeric_to_long(fc_nv, &fc_l)) != 0)
		return fc_i;

/* 实际上这不应该发生 */
#if SIZEOF_LONG > SIZEOF_INT

	if (fc_l < INT_MIN || fc_l > INT_MAX)
	{
		errno = PGTYPES_NUM_OVERFLOW;
		return -1;
	}

#endif

	*fc_ip = (int) fc_l;
	return 0;
}

int PGTYPESnumeric_to_long(numeric *fc_nv, long *fc_lp)
{
	char	   *fc_s = PGTYPESnumeric_to_asc(fc_nv, 0);
	char	   *fc_endptr;

	if (fc_s == NULL)
		return -1;

	errno = 0;
	*fc_lp = strtol(fc_s, &fc_endptr, 10);
	if (fc_endptr == fc_s)
	{
		/* this should not happen actually */
		free(fc_s);
		return -1;
	}
	free(fc_s);
	if (errno == ERANGE)
	{
		if (*fc_lp == LONG_MIN)
			errno = PGTYPES_NUM_UNDERFLOW;
		else
			errno = PGTYPES_NUM_OVERFLOW;
		return -1;
	}
	return 0;
}

int PGTYPESnumeric_to_decimal(numeric *fc_src, decimal *fc_dst)
{
	int			fc_i;

	if (fc_src->ndigits > DECSIZE)
	{
		errno = PGTYPES_NUM_OVERFLOW;
		return -1;
	}

	fc_dst->weight = fc_src->weight;
	fc_dst->rscale = fc_src->rscale;
	fc_dst->dscale = fc_src->dscale;
	fc_dst->sign = fc_src->sign;
	fc_dst->ndigits = fc_src->ndigits;

	for (fc_i = 0; fc_i < fc_src->ndigits; fc_i++)
		fc_dst->digits[fc_i] = fc_src->digits[fc_i];

	return 0;
}

int PGTYPESnumeric_from_decimal(decimal *fc_src, numeric *fc_dst)
{
	int			fc_i;

	fc_zero_var(fc_dst);

	fc_dst->weight = fc_src->weight;
	fc_dst->rscale = fc_src->rscale;
	fc_dst->dscale = fc_src->dscale;
	fc_dst->sign = fc_src->sign;

	if (fc_alloc_var(fc_dst, fc_src->ndigits) != 0)
		return -1;

	for (fc_i = 0; fc_i < fc_src->ndigits; fc_i++)
		fc_dst->digits[fc_i] = fc_src->digits[fc_i];

	return 0;
}
